package dyyx.rule;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.lang.StringUtils;

public class RuleSqlUtil {
	
	
	public static final String DATE_FORMAT = "yyyyMMddHHmmssSSS";
	
	private static final Random rand = new Random();
	
	
	public static final String SEP = "x";

	

	
	private static final String SPACE = " ";
	// private static final String EMPTY = "";

	private static final String TAB = "\t";

	
	private static final String POLICY_SET = "salaxy_policy_set";
	private static final String POLICY = "salaxy_policy";
	private static final String RULE = "salaxy_rule";
	private static final String RULE_CONDITION = "salaxy_rule_condition_element";
	
	private static final String deal_type_mapping = "[{\"dealType\":\"Accept\",\"score\":30},{\"dealType\":\"Review\",\"score\":50},{\"dealType\":\"Reject\",\"score\":100}]";

	private static final String policy_set_type = "normal";
	private static final String partner_code = "kratos";
	private static final String event_type = "Login";
	private static final String policy_status = "publish";
	private static final String policy_mode = "Weighted";
	// risk_type suspiciousLogin
	private static final String risk_type = "suspiciousLogin";
	
	private static final String app_name  = "test03";


 
	private static final AtomicLong seq = new AtomicLong(0);

	
	
	private static final Map<String,String> fieldsMap = new HashMap<String,String>();
	private static final Map<String,List<String>> fieldListMap = new HashMap<String,List<String>>();

	
	private static final String[]TABLES = new String[]{POLICY_SET,POLICY,RULE,RULE_CONDITION};

	
	private static final Set<String> ignoreFields = new HashSet<String>();
	
	
	
	static{
		fieldsMap.put(POLICY_SET, "id	uuid	name	app_name	event_type	event_id	description	partner_code	status	create_by	update_by	gmt_create	gmt_modified	type	en_name");
		fieldsMap.put(POLICY, "id	uuid	gmt_create	gmt_modified	name	status	risk_event_id	risk_event_type	mode	deny_threshold	review_threshold	app_name	create_by	updated_by	version	partner	is_policy_template	business_type	description	app_type	risk_type	level	fk_policy_set_uuid	partner_type	deal_level	begin_threshold	end_threshold	deal_type_mapping	en_name	tags");
		fieldsMap.put(RULE, "id	uuid	gmt_create	gmt_modified	name	valid	cause_code	operate_code	gmt_begin	gmt_end	priority	risk_weight	weight_ratio	weight_operator	weight_type	weight_index	display_order	fk_policy_uuid	parent_uuid	if_clause	template	triggers	apply_status	apply_type	fk_deal_type_uuid	custom_id	operation_actions	en_name	back_test");
		fieldsMap.put(RULE_CONDITION, "id	uuid	gmt_create	gmt_modified	parent_uuid	logic_operator	property	property_data_type	operator	value	type	params	created_by	updated_by	description	fk_rule_uuid	version	right_value_type	describe");
	
		buildFieldListMap();
		
		ignoreFields.add("id");
		ignoreFields.add("gmt_create");
		ignoreFields.add("gmt_modified");

		
	}
	
	
	public static String getTimeStringOfUUID()throws Exception {
		return getDateString(new Date(),null);
	}
	
	public static String getTimeStringOfUUID(long time)throws Exception {
		return getDateString(new Date(time),null);
	}
	
	public static String getDateString(Date date, String format) throws Exception {
		if (date == null) {
			return null;
		}
		if (StringUtils.isBlank(format)) {
			format = DATE_FORMAT;
		}

		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(date);
	}
	
	
	private static List<String> getFieldList(String str){
		if(StringUtils.isBlank(str)){
			return null;
		}
		str = StringUtils.replace(str, TAB, SPACE);
		String[]arr = StringUtils.split(str, SPACE);
		if(arr==null || arr.length<=0){
			return null;
		}
		List<String> list = new ArrayList<String>();
		for(String item:arr){
			if(StringUtils.isBlank(item)){
				continue;
			}
			item = item.trim();
			list.add(item);
		}
		
		return list;
	}
	
	private static void buildFieldListMap(String  table){
		String str = fieldsMap.get(table);
		List<String> list = getFieldList(str);
		if(list==null || list.isEmpty()){
			return;
		}
		fieldListMap.put(table, list);
	}
	
	private static void buildFieldListMap(){
		for(String table:TABLES){
			buildFieldListMap(table);
		}
	}
	
	
	public static String buildInsertSql(String table,Map<String,String> map)throws Exception{
		List<String> list = fieldListMap.get(table);
		if(list==null || list.isEmpty()){
			throw new Exception("fieldList is empty,table="+table);
		}
		
		List<String> fields = new ArrayList<String>();
		List<String> values = new ArrayList<String>();

		String value = null;
		for(String item:list){
			if(StringUtils.isBlank(item)){
				continue;
			}
			value = map.get(item);
			if(StringUtils.isBlank(value)){
				continue;
			}
			// TODO 特殊字段处理
			fields.add(item);
			values.add("'"+value+"'");
		}
		if(values.size()<=3){
		    throw new Exception("value list size error");
		}
	
		return buildInsertSql(table,fields,values);
	}
	
	private static String buildInsertSql(String table,List<String> fields,List<String> values)throws Exception{		
		StringBuilder sb = new StringBuilder();		
		sb.append("insert into ").append(table).append("(");
		sb.append(StringUtils.join(fields, ",")).append(") values(");
		sb.append(StringUtils.join(values, ",")).append(")");
		return sb.toString();
	}
	
	public static String getSeqStr(){
		return getString(seq.getAndIncrement(),3);
	}
	
	
	public static String getUUID(String prefix)throws Exception{
		return getUUID(prefix,32);
	}

	
	public static String getUUID(String prefix,int totalLength)throws Exception{
		
		if(totalLength<32){
			totalLength = 32;
		}
		
		StringBuilder sb = new StringBuilder();
		sb.append(prefix).append(getTimeStringOfUUID());
		sb.append(SEP).append(getSeqStr()).append(SEP);
		int tmp = totalLength - sb.length();
		if(tmp < 0){
			throw new Exception("uuid too long");
		}
		sb.append(getString(rand.nextLong(),tmp));
		
		return sb.toString();
		
	}
	
	
	public static String getUUID()throws Exception{
		return getUUID("xxx");
	}

	
	private static String getString(long value,int len){
		if(len<=0){
			len=1;
		}
		if(value<0){
			value = Math.abs(value);
		}
		
		String str = String.valueOf(value);
		int size = str.length();
		if(size==len){
			return str;
		}
		if(size > len){
			return str.substring(size - len);
		}
		
		int num = len - size;
		StringBuilder sb = new StringBuilder();
		
		for(int i=0;i<num;i++){
			sb.append("0");
		}
		
		sb.append(str);
		
		return sb.toString();
	}
	
	
	public static String getPolicySetName() throws Exception {
		return getUUID("policyset",36);
	}
	public static String getPolicyName() throws Exception {
		return getUUID("policy",36);
	}
	
	
	
	public static String getEventId() throws Exception {
		StringBuilder sb = new StringBuilder();
		sb.append("event").append(getTimeStringOfUUID());
		sb.append(SEP).append(getSeqStr());
		// append(getString(rand.nextLong(),6));
		
		return sb.toString();
 
	} 
	
	public static String getRuleName() throws Exception {
		// 规则名字长度不能超过24
		String uuid = getUUID();
		return "r" + uuid.substring(uuid.length() - 22);
		
	}
		
	
	public static void buildSql(RuleSqlContext ctx)throws Exception{
		buildPolicySetSql(ctx);
		buildPolicySql(ctx);
		for(int i=0;i<ctx.count;i++){
			buildRuleSql(ctx);
			buildRuleConditionSql(ctx);
		}
	}
	
	
	public static void buildPolicySetSql(RuleSqlContext ctx)throws Exception{
		String policySetUuid = getUUID();
		ctx.policySetUuid = policySetUuid;
		String eventId = getEventId();
		ctx.eventId = eventId;
		Map<String,String> map = new HashMap<String,String>();
		map.put("uuid", policySetUuid);
		// map.put("name", getPolicySetName());
		map.put("name", "policyset_"+policySetUuid);
		map.put("app_name", app_name);
		map.put("event_type", event_type);
		map.put("event_id",  eventId);
		map.put("description", "desc");
		map.put("partner_code", partner_code);
		map.put("status", "1");
		map.put("type", policy_set_type);
		// map.put("en_name", policySetUuid);		
		String sql = buildInsertSql(POLICY_SET,map);	
		ctx.policySetSql = sql;	
	}
	
    public static void buildPolicySql(RuleSqlContext ctx)throws Exception{
    	String policySetUuid = ctx.policySetUuid;
		String policyUuid = getUUID();
		ctx.policyUuid = policyUuid;
		String eventId = ctx.eventId;
		
		Map<String,String> map = new HashMap<String,String>();
		map.put("uuid", policyUuid);
		map.put("name", "policy_"+policyUuid);
		map.put("status", "publish");
		map.put("risk_event_id", eventId);
		map.put("risk_event_type",  "Login");
		map.put("mode", "Weighted");
		map.put("app_name", app_name);
		map.put("deny_threshold", "0");
		map.put("review_threshold", "0");
		map.put("partner", partner_code);
		// map.put("is_policy_template", "0");
		map.put("risk_type", "suspiciousLogin");
		map.put("level", "0");
		map.put("fk_policy_set_uuid", policySetUuid);
		map.put("deal_type_mapping", deal_type_mapping);
		// map.put("", "");
		
		// map.put("en_name", policySetUuid);		
		String sql = buildInsertSql(POLICY,map);	
		ctx.policySql = sql;	
	}
    
    public static void buildRuleSql(RuleSqlContext ctx)throws Exception{
    	String policyUuid = ctx.policyUuid;
    	String ruleUuid = getUUID();
    	ctx.ruleUuid = ruleUuid;
    	
		Map<String,String> map = new HashMap<String,String>();
		map.put("uuid", ruleUuid);
		map.put("name", getRuleName());
		map.put("valid", "1");
		map.put("risk_weight", "1");
		map.put("weight_ratio", "0");
		map.put("weight_operator", "add");
		map.put("weight_type", "salaxyZb");
		map.put("display_order", ctx.getRuleDisplayOrder()+"");
		map.put("fk_policy_uuid",policyUuid);
		map.put("template", "common/custom");
		// 规则编号
		// map.put("custom_id", "");
		map.put("operation_actions", "[]");
		//map.put("", "");


		
		String sql = buildInsertSql(RULE,map);
		
		ctx.ruleSqls.add(sql);
    	
		
	}
    
    public static void buildRuleConditionSql(RuleSqlContext ctx)throws Exception{
    	String policyUuid = ctx.policyUuid;
    	String ruleUuid = ctx.ruleUuid;
    	
    	String ruleConditionParentUuid = getUUID();
    	String ruleConditionUuid = getUUID();
    	
    	ctx.ruleConditionParentUuid = ruleConditionParentUuid;
    	ctx.ruleConditionUuid = ruleConditionUuid;
    	
    	// 
    	
    	Map<String,String> map = new HashMap<String,String>();
		map.put("uuid", ruleConditionParentUuid);
		
		// map.put("parent_uuid", ruleConditionParentUuid);
		map.put("logic_operator", "&&");
		// map.put("property", "S_M_VB_MERCHANTNO");
		// map.put("property_data_type", "STRING");
		// map.put("operator", "==");
		// map.put("value", "");
		map.put("type", "context");
		map.put("params", "[]");
		map.put("fk_rule_uuid", ruleUuid);
		// map.put("right_value_type", "input");
		
        String sql = buildInsertSql(RULE_CONDITION,map);
		
		ctx.ruleSqls.add(sql);
    	
    	// 
		
		map = new HashMap<String,String>();
        map.put("uuid", ruleConditionUuid);

		map.put("parent_uuid", ruleConditionParentUuid);

		map.put("logic_operator", "&&");
		map.put("property", "S_M_VB_MERCHANTNO");
		map.put("property_data_type", "STRING");
		map.put("operator", "==");
		map.put("value", "123456");
		map.put("type", "context");
		map.put("params", "[]");
		map.put("fk_rule_uuid", ruleUuid);
		map.put("right_value_type", "input");
		
        sql = buildInsertSql(RULE_CONDITION,map);
		
		ctx.ruleSqls.add(sql);

		
   	}

	
	public static void main(String[] args) throws Exception {
		
		    String ruleName = getRuleName();
		    System.out.println(ruleName.length()+" "+ruleName);
		
			System.out.println(fieldListMap);
			List<String> list = fieldListMap.get(RULE);
			System.out.println(list.size());
			System.out.println(StringUtils.join(list, ","));


			for(String table:TABLES){
				list = fieldListMap.get(table);
				System.out.println(table+"="+list.size());
				System.out.println(StringUtils.join(list, ","));
			}
			
			Map<String,String> map = new HashMap<String,String>();
			map.put("uuid", "uuid001");
			map.put("name", "name001");
			map.put("app_name", "app001");
			map.put("event_id", "event001");
			
			String sql = buildInsertSql(POLICY_SET,map);
			
			System.out.println(sql);
			
			String str = getTimeStringOfUUID();
			System.out.println(str.length());
			System.out.println(str);

			System.out.println(System.currentTimeMillis());
			
			long now = System.currentTimeMillis();
			str = getTimeStringOfUUID(now);
			
			System.out.println(now);
			System.out.println(str);
			
			String uuid = "6d943135bc1842069353e8acf826bb81";
			System.out.println(uuid);
			System.out.println(uuid.length());
			
			
			System.out.println(rand.nextLong());

			
			System.out.println(getString(0,3));
			System.out.println(getString(1,3));
			System.out.println(getString(11,3));
			System.out.println(getString(111,3));
			System.out.println(getString(1111,3));
			System.out.println(getString(-1,3));
			System.out.println(getString(-11,3));
			System.out.println(getString(-111,3));
			System.out.println(getString(-1111,3));
			
			

			uuid = getUUID("rulec");
			System.out.println(uuid.length());
			System.out.println(uuid);
			
			uuid = getUUID("polic");
			System.out.println(uuid.length());
			System.out.println(uuid);
			
			uuid = getUUID("polis");
			System.out.println(uuid.length());
			System.out.println(uuid);
			
			uuid = getUUID("rulei");
			System.out.println(uuid.length());
			System.out.println(uuid);
			
			for(int i=0;i<10;i++){
				uuid = getUUID();
				System.out.println(uuid.length()+" "+uuid +" "+getEventId());
			}
			
			
			RuleSqlContext ctx = new RuleSqlContext();
			buildPolicySetSql(ctx);
			System.out.println(ctx.policySetUuid+" "+ctx.eventId);
			System.out.println(ctx.policySetSql);
			
			buildPolicySql(ctx);
			System.out.println(ctx.policyUuid+" "+ctx.policyUuid);
			System.out.println(ctx.policySql);
			
			buildRuleSql(ctx);
			System.out.println(ctx.ruleUuid);
			
			buildRuleConditionSql(ctx);
			System.out.println(ctx.ruleConditionParentUuid);
			System.out.println(ctx.ruleConditionUuid);


			for(String item:ctx.ruleSqls){
				System.out.println(item);
			}
			
			System.out.println("==========\n\n\n");
			
			ctx = new RuleSqlContext();
			ctx.count = 100;
			buildSql(ctx);
			System.out.println("use spartan1010;");
			System.out.println(ctx.toSql());
			


	}
}
